package shooter.models;

import java.awt.Graphics2D;
import java.awt.image.BufferedImage;

import shooter.Images;
import shooter.handler.GameEventListener;

/**
 * This class initializes a player for the game.
 * 
 * @author Michail Tausch
 */
public class Player extends Sprite {

	boolean up;
	boolean down;
	boolean left;
	boolean right;
	boolean strafeRight;
	boolean strafeLeft;

	boolean shoot;
	boolean fire = true;
	boolean rearm = false;
	boolean sM = false;
		
	BufferedImage shotImage;

	int statsKills = 0;
	int statsDeaths = 0;
	int spree = 0;
	public long ping = 0;

	long lastShot;
	boolean hasShot;

	boolean knife = false;
	boolean click = false;

	double dxShot;
	double dyShot;

	double ankat;
	double gegenkat;

	double lastX = 0.0;
	double lastY = 0.0;
	double startX = 0.0;
	double startY = 0.0;
	public double reloadTime = 0.0;

	int id = 0;
	int team = 0;

	int weaponMode = 1;
	int hp = 100;

	String name = "";

	int[][] weaponStuff;
	

	/**
	 * The constructor of this class. Creates a player.
	 * @param id
	 * @param team
	 * @param x
	 * @param y
	 * @param name
	 * @param sM
	 */
	public Player(int id, int team, double x, double y, String name, boolean sM) {
		super(id, x, y);
		dx = 0;
		dy = 0;
		this.id = id;
		this.startX = x;
		this.startY = y;
		this.name = name;
		this.team = team;
		this.sM = sM;

		if (sM) {
			this.setWeaponMode(5);
		}

		lastShot = 0;
		hasShot = false;

		dxShot = Images.playersRot[getWeaponMode()].getWidth() - 20;
		dyShot = (Images.playersRot[getWeaponMode()].getWidth() / 2.0) + 7;

		weaponStuff = new int[11][6];
		for (int k = 0; k < 10; k++) {
			weaponStuff[k][0] = k;
		}
		weaponStuff[0][4] = 500;
		weaponStuff[0][5] = 25;
		weaponStuff[1][1] = 60;
		weaponStuff[1][2] = 30;
		weaponStuff[1][3] = 30;
		weaponStuff[1][4] = 300;
		weaponStuff[1][5] = 35;
		weaponStuff[2][1] = 35;
		weaponStuff[2][2] = 7;
		weaponStuff[2][3] = 7;
		weaponStuff[2][4] = 600;
		weaponStuff[2][5] = 30;
		weaponStuff[3][1] = 50;
		weaponStuff[3][2] = 50;
		weaponStuff[3][3] = 50;
		weaponStuff[3][4] = 200;
		weaponStuff[3][5] = 20;
		weaponStuff[4][1] = 30;
		weaponStuff[4][2] = 10;
		weaponStuff[4][3] = 10;
		weaponStuff[4][4] = 3000;
		weaponStuff[4][5] = 100;
		weaponStuff[5][1] = 1;
		weaponStuff[5][2] = 1;
		weaponStuff[5][3] = 1;
		weaponStuff[5][4] = 1000;
		weaponStuff[5][5] = 100;
		weaponStuff[10][4] = 300;

	}
	
	/**
	 * Returns the value whether the player strafes right.
	 * @return
	 */
	public boolean isStraferight() {
		return strafeRight;
	}
	
	/**
	 * Sets the value for straferight.
	 * @param straferight
	 */
	public void setStraferight(boolean straferight) {
		this.strafeRight = straferight;
	}
	
	/**
	 * Returns the value whether the player strafes left.
	 * @return
	 */
	public boolean isStrafeleft() {
		return strafeLeft;
	}
	
	/**
	 * Sets the value for strafeleft.
	 * @param strafeleft
	 */
	public void setStrafeleft(boolean strafeleft) {
		this.strafeLeft = strafeleft;
	}

	/**
	 * Should the player move up?
	 * 
	 * @return true if yes, false otherwise
	 */
	public boolean isUp() {
		return up;
	}

	/**
	 * Sets the player to move up.
	 * 
	 * @param up
	 *            true if yes, false otherwise
	 */
	public void setUp(boolean up) {
		this.up = up;
	}

	/**
	 * Should the player move down?
	 * 
	 * @return true if yes, false otherwise
	 */
	public boolean isDown() {
		return down;
	}

	/**
	 * Sets the player to move down.
	 * 
	 * @param up
	 *            true if yes, false otherwise
	 */
	public void setDown(boolean down) {
		this.down = down;
	}

	/**
	 * Should the player move left?
	 * 
	 * @return true if yes, false otherwise
	 */
	public boolean isLeft() {
		return left;
	}

	/**
	 * Sets the player to move left.
	 * 
	 * @param up
	 *            true if yes, false otherwise
	 */
	public void setLeft(boolean left) {
		this.left = left;
	}

	/**
	 * Should the player move right?
	 * 
	 * @return true if yes, false otherwise
	 */
	public boolean isRight() {
		return right;
	}

	/**
	 * Sets the player to move right.
	 * 
	 * @param up
	 *            true if yes, false otherwise
	 */
	public void setRight(boolean right) {
		this.right = right;
	}

	/**
	 * Should the player shoot?
	 * 
	 * @return true if yes, false otherwise
	 */
	public boolean isShoot() {
		return shoot;
	}

	/**
	 * Sets the player to shoot.
	 * 
	 * @param up
	 *            true if yes, false otherwise
	 */
	public void setShoot(boolean shoot) {
		this.shoot = shoot;
	}

	/**
	 * If it is called the player moves.
	 */
	@Override
	public void move(long milliSecondsElapsed) {
		if (left) {
			angle -= milliSecondsElapsed * 0.1;
		}

		if (right) {
			angle += milliSecondsElapsed * 0.1;
		}

		rotate = true;
		dx = 0;
		dy = 0;
		dangle = 0;

		ankat = Math.cos(((angle - 90) / 180) * Math.PI);
		gegenkat = Math.sin(((angle - 90) / 180) * Math.PI);

		if (up) {
			dx = 0.1 * ankat;
			dy = 0.1 * gegenkat;
		}

		if (down) {
			dx = -0.1 * ankat;
			dy = -0.1 * gegenkat;
		}

		if (strafeLeft) {
			dx = 0.1 * Math.cos(((angle - 180) / 180) * Math.PI);
			dy = 0.1 * Math.sin(((angle - 180) / 180) * Math.PI);
		}

		if (strafeRight) {
			dx = 0.1 * Math.cos(((angle) / 180) * Math.PI);
			dy = 0.1 * Math.sin(((angle) / 180) * Math.PI);
		}

		lastX = x;
		lastY = y;
		super.move(milliSecondsElapsed);
	}

	/**
	 * Fires a shot if isShoot() is true.
	 * 
	 * @param milliSecondsElapsed
	 *            the milliseconds elapsed
	 */
	public void doActions(long milliSecondsElapsed, GameEventListener controller) {
		lastShot += milliSecondsElapsed;
		if (weaponStuff[getWeaponMode()][2] > 0 && fire) {
			if (shoot) {
				if (!hasShot || lastShot >= weaponStuff[getWeaponMode()][4]) {
					hasShot = true;
					lastShot = 0;
					Shot shot =
							new Shot(this.id, x + (this.getWidth() / 2) - 2, y
									+ (this.getHeight() / 2) - 5);
					ankat = Math.cos(((angle - 90) / 180) * Math.PI);
					gegenkat = Math.sin(((angle - 90) / 180) * Math.PI);

					shot.setAngle(angle);
					shot.setRotate(true);

					shot.setHorizontalMovement(ankat);
					shot.setVerticalMovement(gegenkat);
					controller.newShot(shot, this);

					if (weaponStuff[getWeaponMode()][2] > 0) {
						this.weaponStuff[getWeaponMode()][2] =
								weaponStuff[getWeaponMode()][2] - 1;
					}
				}
			}
		}
		if (fire == false) {
			if (shoot) {
				if (!hasShot || lastShot >= weaponStuff[getWeaponMode()][4]) {
					hasShot = true;
					lastShot = 0;
					this.knife = true;
				}
			}
		}
		if (weaponStuff[getWeaponMode()][1] == 0
				&& weaponStuff[getWeaponMode()][2] == 0 && fire == true) {
			if (shoot) {
				if (!hasShot || lastShot >= weaponStuff[10][4]) {
					hasShot = true;
					lastShot = 0;
					this.click = true;
				}
			}
		}
	}
	
	/**
	 * Is the player shooting?
	 * @return true if yes
	 */
	public boolean isFire() {
		return fire;
	}
	
	/**
	 * Sets whether the player should shoot or not. 
	 * @param fire
	 */
	public void setFire(boolean fire) {
		this.fire = fire;
	}

	/**
	 * Rearms the player and his current weapon.
	 */
	public void rearm() {
		if (this.weaponStuff[getWeaponMode()][3] <= weaponStuff[getWeaponMode()][1]) {
			this.weaponStuff[getWeaponMode()][1] =
					weaponStuff[getWeaponMode()][1]
							- (weaponStuff[getWeaponMode()][3] - weaponStuff[getWeaponMode()][2]);
			this.weaponStuff[getWeaponMode()][2] =
					weaponStuff[getWeaponMode()][3];
		} else {
			this.weaponStuff[getWeaponMode()][2] =
					weaponStuff[getWeaponMode()][1];
			this.weaponStuff[getWeaponMode()][1] = 0;
		}

	}
	
	/**
	 * Returns the value of the ankat.
	 * @return
	 */
	public double getAnkat() {
		return ankat;
	}
	
	/**
	 * Sets the value of the ankat.
	 * @param ankat
	 */
	public void setAnkat(double ankat) {
		this.ankat = ankat;
	}
	
	/**
	 * Returns the value of gegenkat.
	 * @return
	 */
	public double getGegenkat() {
		return gegenkat;
	}

	/**
	 * Sets the value gegenkat.
	 * @param gegenkat
	 */
	public void setGegenkat(double gegenkat) {
		this.gegenkat = gegenkat;
	}
	
	/**
	 * Returns the x position of the player before.
	 * @return
	 */
	public double getLastX() {
		return lastX;
	}
	
	/**
	 * Sets the last x position of the player.
	 * @param lastX
	 */
	public void setLastX(double lastX) {
		this.lastX = lastX;
	}
	
	/**
	 * Gets the last y position of the player.
	 * @return
	 */
	public double getLastY() {
		return lastY;
	}
	
	/**
	 * Sets the last y position of the player.
	 * @param lastY
	 */
	public void setLastY(double lastY) {
		this.lastY = lastY;
	}
	
	/**
	 * Returns the current health points of the player.
	 * @return
	 */
	public int getHp() {
		return hp;
	}
	
	/**
	 * Sets the current health points of the player.
	 * @param hp
	 */
	public void setHp(int hp) {
		this.hp = hp;
	}
	
	/**
	 * Returns the id of the player.
	 */
	public int getId() {
		return id;
	}
	
	/**
	 * Sets the id of the player.
	 */
	public void setId(int id) {
		this.id = id;
	}
	
	/**
	 * Inherited method.
	 */
	@Override
	public void collidedWith(Sprite sprite) {
	}
	
	/**
	 * Paints the player image on the screen.
	 */
	public void draw(Graphics2D g) {
		super.draw(g);
	}
	
	/**
	 * Returns the array of with weapon info of the player.
	 * @return
	 */
	public int[][] getWeaponStuff() {
		return weaponStuff;
	}
	
	/**
	 * Sets the array with the weapon info of the player.
	 * @param row
	 * @param collumn
	 * @param value
	 */
	public void setWeaponStuff(int row, int collumn, int value) {
		this.weaponStuff[row][collumn] = value;
	}
	
	/**
	 * Is the current weapon of the player?
	 * @return
	 */
	public boolean isKnife() {
		return knife;
	}
	
	/**
	 * Sets the current weapon of the player to knife.
	 * @param knife
	 */
	public void setKnife(boolean knife) {
		this.knife = knife;
	}
	
	/**
	 * Returns the current weapon of the player.
	 * @return
	 */
	public int getWeaponMode() {
		return weaponMode;
	}

	/**
	 * Sets the current weapon of the player.
	 * @param weaponMode
	 */
	public void setWeaponMode(int weaponMode) {
		this.weaponMode = weaponMode;
	}
	
	/**
	 * Is the current weapon of the player empty?
	 * @return
	 */
	public boolean isClick() {
		return click;
	}
	
	/**
	 * Sets the value click.
	 * @param click
	 */
	public void setClick(boolean click) {
		this.click = click;
	}
	
	/**
	 * Returns the start x position of the player.
	 * @return
	 */
	public double getStartX() {
		return startX;
	}
	
	/**
	 * Sets the start x position of the player.
	 * @param startX
	 */
	public void setStartX(double startX) {
		this.startX = startX;
	}
	
	/**
	 * Returns the start y position of the player.
	 * @return
	 */
	public double getStartY() {
		return startY;
	}
	
	/**
	 * Sets the start y position of the player. 
	 * @param startY
	 */
	public void setStartY(double startY) {
		this.startY = startY;
	}
	
	/**
	 * Is the player reloarding?
	 * @return
	 */
	public boolean isRearm() {
		return rearm;
	}
	
	/**
	 * Forces the player to rearm.
	 * @param rearm
	 */
	public void setRearm(boolean rearm) {
		this.rearm = rearm;
	}
	
	/**
	 * Returns the number of kills.
	 * @return
	 */
	public int getStatsKills() {
		return statsKills;
	}

	/**
	 * Sets the number of kills.
	 * @param statsKills
	 */
	public void setStatsKills(int statsKills) {
		this.statsKills = statsKills;
	}

	/**
	 * Returns the number of deaths.
	 * @return
	 */
	public int getStatsDeaths() {
		return statsDeaths;
	}

	/**
	 * Sets the number of deaths.
	 * @param statsDeaths
	 */
	public void setStatsDeaths(int statsDeaths) {
		this.statsDeaths = statsDeaths;
	}

	/**
	 * Returns the ping of the player.
	 * @return
	 */
	public long getPing() {
		return ping;
	}

	/**
	 * Sets the ping of the player.
	 * @param ping
	 */
	public void setPing(long ping) {
		this.ping = ping;
	}

	/**
	 * Returns the name of the player.
	 * @return
	 */
	public String getName() {
		return name;
	}

	/**
	 * Sets the name of the player.
	 * @param name
	 */
	public void setName(String name) {
		this.name = name;
	}
	
	/**
	 * Returns the current spree.
	 * @return
	 */
	public int getSpree() {
		return spree;
	}
	
	/**
	 * Sets the spree.
	 * @param spree
	 */
	public void setSpree(int spree) {
		this.spree = spree;
	}
	
	/**
	 * Returns the team id.
	 * @return
	 */
	public int getTeam() {
		return team;
	}
	
	/**
	 * Sets the team id.
	 * @param team
	 */
	public void setTeam(int team) {
		this.team = team;
	}

	/**
	 * Returns the image of the player.
	 */
	public BufferedImage getImage() {
		if (team == 1) {
			return Images.playersRot[getWeaponMode()];
		} else {
			return Images.playersBlau[getWeaponMode()];
		}
	}

	/**
	 * Returns a String.
	 */
	@Override
	public String toString() {
		StringBuilder result = new StringBuilder(getName());
		result.append(" ");
		result.append(getX());
		result.append(" ");
		result.append(getY());
		result.append("\n");
		return result.toString();
	}
}
